﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ManagedWinapi.Windows;
using System.Net.Mail;

namespace wutils
{

    public enum EventAction
    {
        ADDED, REMOVED
    }
    public class WindowEventArgs : EventArgs
    {
        public SystemWindow Window { get; set; }
        public EventAction Action { get; set; }

        public WindowEventArgs(SystemWindow window, EventAction action)
        {
            Action = action;
            Window = window;
        }
    }

    public static class WindowUtils
    {
        #region Properties
        
        private readonly static Dictionary<IntPtr, SystemWindow> _minimizedWindows = new Dictionary<IntPtr, SystemWindow>();
        private readonly static Dictionary<IntPtr, SystemWindow> _onTopWindows = new Dictionary<IntPtr, SystemWindow>();

        public static IEnumerable<SystemWindow> MinimizedWindows
        {
            get { return _minimizedWindows.Values; }
        }
        public static IEnumerable<SystemWindow> OnTopWindows
        {
            get { return _onTopWindows.Values; }
        }
    
        #endregion
        
        #region Events

        public static event EventHandler<WindowEventArgs> MinimizedWindowsChanged;
        public static event EventHandler<WindowEventArgs> OnTopWindowsChanged;

        private static void OnRaiseMinimizedWindowsChangedEvent(WindowEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<WindowEventArgs> handler = MinimizedWindowsChanged;

            RaiseEvent(handler, e);
        }
        private static void OnRaiseOnTopWindowsChangedEvent(WindowEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<WindowEventArgs> handler = OnTopWindowsChanged;

            RaiseEvent(handler, e);
        }
        private static void RaiseEvent(EventHandler<WindowEventArgs> handler, WindowEventArgs e)
        {
            // Event will be null if there are no subscribers
            if (handler != null)
            {
                // Use the () operator to raise the event.
                handler(null, e);
            }
        }

        #endregion

        #region Important Stuff

        public static bool SendToTray(SystemWindow window)
        {
            if (!WindowRules.IsAllowed(window))
                throw new DisallowedWindowException();
            
            if (_minimizedWindows.Keys.Contains(window.HWnd)) return false;

            window.VisibilityFlag = false;
            AddMinimizedWindow(window);

            return true;
        }
        public static bool Restore(SystemWindow window)
        {
            if (!WindowRules.IsAllowed(window))
                throw new DisallowedWindowException();

            if (!_minimizedWindows.Keys.Contains(window.HWnd)) return false;

            window = _minimizedWindows[window.HWnd];
            window.VisibilityFlag = true;
            RemoveMinimizedWindow(window);

            return true;
        }
        public static bool ToggleOnTop(SystemWindow window)
        {
            if (window.TopMost) return UnsetOnTop(window);
            else return SetOnTop(window);
        }
        public static bool SetOnTop(SystemWindow window)
        {
            if (!WindowRules.IsAllowed(window))
                throw new DisallowedWindowException();

            if (_onTopWindows.Keys.Contains(window.HWnd)) return false;
            
            window.TopMost = true;
            AddOnTopWindow(window);

            return true;
        }
        public static bool UnsetOnTop(SystemWindow window)
        {
            if (!WindowRules.IsAllowed(window))
                throw new DisallowedWindowException();
            
            if (!_onTopWindows.Keys.Contains(window.HWnd)) return false;
            
            window = _onTopWindows[window.HWnd];
            window.TopMost = false;
            RemoveOnTopWindow(window);
            
            return true;
        }
        public static void ResetAll()
        {
            List<SystemWindow> windows = new List<SystemWindow>();
            windows.AddRange(OnTopWindows);
            foreach (SystemWindow window in windows)
            {
                UnsetOnTop(window);
            }
            windows.RemoveRange(0, windows.Count);
            windows.AddRange(MinimizedWindows);
            foreach (SystemWindow window in windows)
            {
                Restore(window);
            }
        }

        #endregion

        #region Dictionary Operations

        private static void AddMinimizedWindow(SystemWindow window)
        {
            _minimizedWindows.Add(window.HWnd, window);
            OnRaiseMinimizedWindowsChangedEvent(new WindowEventArgs(window, EventAction.ADDED));
        }
        private static void RemoveMinimizedWindow(SystemWindow window)
        {
            _minimizedWindows.Remove(window.HWnd);
            OnRaiseMinimizedWindowsChangedEvent(new WindowEventArgs(window, EventAction.REMOVED));
        }
        private static void AddOnTopWindow(SystemWindow window)
        {
            _onTopWindows.Add(window.HWnd, window);
            OnRaiseOnTopWindowsChangedEvent(new WindowEventArgs(window, EventAction.ADDED));
        }
        private static void RemoveOnTopWindow(SystemWindow window)
        {
            _onTopWindows.Remove(window.HWnd);
            OnRaiseOnTopWindowsChangedEvent(new WindowEventArgs(window, EventAction.REMOVED));
        }

        #endregion
    }
}
